home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 326-350 / disk_327 / msh / src / hanlock.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  18KB  |  744 lines

  1. /*-
  2.  * $Id: hanlock.c,v 1.4 90/01/27 20:22:17 Rhialto Exp $
  3.  * $Log:    hanlock.c,v $
  4.  * Revision 1.4  90/01/27  20:22:17  Rhialto
  5.  * Added extra check when freeing MSFileLocks.
  6.  * 
  7.  * Revision 1.3  90/01/23  00:36:57  Rhialto
  8.  * Add an #ifndef READONLY.
  9.  *
  10.  * Revision 1.2  89/12/17  23:05:33  Rhialto
  11.  * Add MSSetProtect
  12.  *
  13.  * Revision 1.1  89/12/17  20:03:01  Rhialto
  14.  *
  15.  * HANLOCK.C
  16.  *
  17.  * The code for the messydos file system handler
  18.  *
  19.  * The Lock department. Takes care of operations on locks, and consequently,
  20.  * on directories.
  21.  *
  22.  * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
  23.  * not be used or copied without a licence.
  24. -*/
  25.  
  26. #include "han.h"
  27. #include "dos.h"
  28.  
  29. #ifdef DEBUG
  30. #   define    debug(x)  dbprintf x
  31. #else
  32. #   define    debug(x)
  33. #endif
  34.  
  35. struct LockList *LockList;    /* List of all locked files we have. Note
  36.                  * this is not the same as all locks we
  37.                  * have */
  38. struct MSFileLock *RootLock;    /* Lock on root directory */
  39. struct MSFileLock *EmptyFileLock;    /* 2nd result of MSLock() */
  40.  
  41. struct DirEntry FakeRootDirEntry = {
  42.     {                /* de_Msd */
  43.     "Unnamed ",             /* msd_Name */
  44.     "   ",                  /* msd_Ext */
  45.     ATTR_VOLUMELABEL,    /* msd_Attributes */
  46.     {0},            /* msd_Pad1 */
  47.     0,            /* msd_Time */
  48.     0x21,            /* msd_Date, 1/1/80 */
  49.     0,            /* msd_Cluster */
  50.     0            /* msd_Filesize */
  51.     },
  52.     -1,             /* de_Sector */
  53.     0                /* de_Offset */
  54. };
  55. byte        DotDot[1 + 8 + 3] = "..          ";
  56.  
  57. /*
  58.  * This routine compares a name in a directory entry with a given name
  59.  */
  60.  
  61. int
  62. CompareNames(dir, name)
  63. register struct MsDirEntry *dir;
  64. register byte  *name;
  65. {
  66. #ifdef DEBUG
  67.     if (name[0] == '\\') {
  68.     extern short    DBEnable;
  69.  
  70.     DBEnable = name[1] & 0x0F;
  71.  
  72.     return CMP_END_OF_DIR;
  73.     }
  74. #endif
  75.  
  76.     if (dir->msd_Name[0] & DIR_DELETED_MASK)
  77.     return CMP_FREE_SLOT;
  78.  
  79.     if (dir->msd_Name[0] == 0)
  80.     return CMP_END_OF_DIR;    /* end of directory */
  81.  
  82.     if (dir->msd_Attributes & ATTR_VOLUMELABEL)
  83.     return CMP_NOT_EQUAL;
  84.  
  85.     if (strncmp(dir->msd_Name, name, 8 + 3))
  86.     return CMP_NOT_EQUAL;
  87.  
  88.     if (dir->msd_Attributes & ATTR_DIRECTORY)
  89.     return CMP_OK_DIR;
  90.  
  91.     return CMP_OK_FILE;
  92. }
  93.  
  94. void
  95. NextDirEntry(sector, offset)
  96. register word  *sector;
  97. register word  *offset;
  98. {
  99.     if ((*offset += MS_DIRENTSIZE) >= Disk.bps) {
  100.     *offset = 0;
  101.     if (*sector >= Disk.datablock) {
  102.         /* Must be subdirectory */
  103.         *sector = NextClusteredSector(*sector);
  104.         debug(("NextClusteredSector: %d\n", *sector));
  105.     } else {
  106.         if (++*sector >= Disk.datablock) {
  107.         *sector = SEC_EOF;
  108.         }
  109.     }
  110.     }
  111.     /* else no more work needed */
  112. }
  113.  
  114. /*
  115.  * Get the directory entry following the given one. If requested, we make
  116.  * the directory longer.
  117.  */
  118.  
  119. struct DirEntry *
  120. FindNext(previous, createit)
  121. register struct DirEntry *previous;
  122. int        createit;
  123. {
  124.     byte       *sector;
  125.     word        prevsec = previous->de_Sector;
  126.  
  127.     NextDirEntry(&previous->de_Sector, &previous->de_Offset);
  128.  
  129.     if (previous->de_Sector == SEC_EOF) {
  130.     error = ERROR_OBJECT_NOT_FOUND;
  131. #ifndef READONLY
  132.     if (createit) {
  133.         if (prevsec < Disk.datablock - 1) { /* Should not be necessary */
  134.         previous->de_Sector = prevsec + 1;
  135.         } else if (prevsec >= Disk.datablock) {
  136.         previous->de_Sector = FindFreeSector(prevsec);
  137.         }
  138.         if (previous->de_Sector != SEC_EOF) {
  139.         sector = EmptySec(previous->de_Sector);
  140.         setmem(sector, (int) Disk.bps, 0);
  141.         MarkSecDirty(sector);
  142.         FreeSec(sector);
  143.         setmem(&previous->de_Msd, sizeof (previous->de_Msd), 0);
  144.  
  145.         return previous;
  146.         }
  147.     }
  148. #endif
  149.     } else if (sector = GetSec(previous->de_Sector)) {
  150.     CopyMem(sector + previous->de_Offset, &previous->de_Msd,
  151.         (long) MS_DIRENTSIZE);
  152.     OtherEndianMsd(&previous->de_Msd);
  153.     FreeSec(sector);
  154.  
  155.     return previous;
  156.     }
  157.     return NULL;
  158. }
  159.  
  160. #ifdef DEBUG
  161.  
  162. void
  163. PrintDirEntry(de)
  164. struct DirEntry *de;
  165. {
  166.     debug(("%d,%d ", de->de_Sector, de->de_Offset));
  167.     debug(("%.8s.%.3s attr:%x time:%x date:%x start:%x size:%lx\n",
  168.        de->de_Msd.msd_Name,
  169.        de->de_Msd.msd_Ext,
  170.        de->de_Msd.msd_Attributes,
  171.        de->de_Msd.msd_Time,
  172.        de->de_Msd.msd_Date,
  173.        de->de_Msd.msd_Cluster,
  174.        de->de_Msd.msd_Filesize
  175.        ));
  176. }
  177.  
  178. #endif
  179.  
  180. /*
  181.  * MakeLock makes a struct MSFileLock from a directory entry and the
  182.  * parent directory MSFileLock pointer. It looks if it already has a Lock
  183.  * on it. In that case, it simply increments its reference count, when
  184.  * possible.
  185.  */
  186.  
  187. struct MSFileLock *
  188. MakeLock(parentdir, dir, mode)
  189. struct MSFileLock *parentdir;
  190. struct DirEntry *dir;
  191. ulong        mode;
  192. {
  193.     register struct MSFileLock *fl;
  194.     struct MSFileLock *nextfl;
  195.  
  196.     if (mode != EXCLUSIVE_LOCK || (dir->de_Msd.msd_Attributes & ATTR_DIR))
  197.     mode = SHARED_LOCK;
  198.  
  199. #ifdef DEBUG
  200.     debug(("MakeLock: "));
  201.     PrintDirEntry(dir);
  202. #endif
  203.  
  204.     /*
  205.      * Look through our list to see if we already have it. The criteria
  206.      * for this are: 1. the directory entries are the same or 2. they have
  207.      * the same first cluster and are both directories (which can have
  208.      * multiple directory entries). Sigh.
  209.      */
  210.  
  211.     for (fl = (struct MSFileLock *) LockList->ll_List.mlh_Head;
  212.      nextfl = (struct MSFileLock *) fl->msfl_Node.mln_Succ;
  213.      fl = nextfl) {
  214. #ifdef DEBUG
  215.     debug(("> "));
  216.     PrintDirEntry(&fl->msfl_Msd);
  217. #endif
  218.     if ((fl->msfl_DirSector == dir->de_Sector &&
  219.          fl->msfl_DirOffset == dir->de_Offset) ||
  220.         (fl->msfl_Msd.msd_Cluster == dir->de_Msd.msd_Cluster &&
  221.          (dir->de_Msd.msd_Attributes & ATTR_DIR) &&
  222.          (fl->msfl_Msd.msd_Attributes & ATTR_DIR))
  223.         ) {
  224.         /* Found existing lock on file */
  225.         if (fl->msfl_Refcount < 0 || mode == EXCLUSIVE_LOCK) {
  226.         error = ERROR_OBJECT_IN_USE;
  227.         return NULL;
  228.         }
  229.         fl->msfl_Refcount++;
  230.         return fl;
  231.     }
  232.     }
  233.  
  234.     fl = AllocMem((long) sizeof (*fl), MEMF_PUBLIC);
  235.     if (fl == NULL) {
  236.     error = ERROR_NO_FREE_STORE;
  237.     return NULL;
  238.     }
  239.     fl->msfl_Parent = parentdir ? MSDupLock(parentdir) : NULL;
  240.  
  241.     fl->msfl_Refcount = (mode == EXCLUSIVE_LOCK) ? -1 : 1;
  242.     fl->msfl_DirSector = dir->de_Sector;
  243.     fl->msfl_DirOffset = dir->de_Offset;
  244.     fl->msfl_Msd = dir->de_Msd;
  245.  
  246.     AddHead(&LockList->ll_List, fl);
  247.  
  248.     return fl;
  249. }
  250.  
  251. /*
  252.  * This routine Locks a file. It first searches it in the directory, then
  253.  * lets the rest of the work be done by MakeLock(). If it encounters an
  254.  * empty slot in the directory, it remembers where, in case we need it. If
  255.  * you clear the MODE_CREATEFILE bit in the mode parameter, we fabricate a
  256.  * new MSFileLock from the empty directory entry. It then becomes the
  257.  * caller's responsibility to MSUnLock() it eventually.
  258.  */
  259.  
  260. struct MSFileLock *
  261. MSLock(parentdir, name, mode)
  262. struct MSFileLock *parentdir;
  263. byte           *name;
  264. ulong        mode;
  265. {
  266.     byte       *sector;
  267.     struct MSFileLock *newlock;
  268.     register struct DirEntry *de;
  269.     struct DirEntry sde;
  270.     byte       *nextpart;
  271.     byte        component[8 + 3];    /* Note: not null-terminated */
  272.     int         createit;
  273.     word        freesec;
  274.     word        freeoffset;
  275.  
  276.     de = &sde;
  277.     newlock = NULL;
  278.  
  279.     /*
  280.      * See if we have an absolute path name (starting at the root).
  281.      */
  282.  
  283.     {
  284.     register byte  *colon;
  285.  
  286.     if (colon = index(name, ':')) {
  287.         name = colon + 1;
  288.         parentdir = RootLock;
  289.     }
  290.     }
  291.  
  292.     /*
  293.      * Get a copy of the parent dir lock, so we can walk it over the
  294.      * directory tree.
  295.      */
  296.     parentdir = MSDupLock(parentdir);
  297.  
  298.     /*
  299.      * Start with the directory entry of the parent dir.
  300.      */
  301.  
  302.     sde.de_Msd = parentdir->msfl_Msd;
  303.     sde.de_Sector = parentdir->msfl_DirSector;
  304.     sde.de_Offset = parentdir->msfl_DirOffset;
  305. #ifdef DEBUG
  306.     debug(("pdir %08lx: ", parentdir));
  307.     PrintDirEntry(&parentdir->msfl_Msd);
  308. #endif
  309.  
  310. newdir:
  311.     freesec = SEC_EOF;        /* Means none found yet */
  312.  
  313.     nextpart = ToMSName(component, name);
  314.     debug(("Component: '%11s'\n", component));
  315.     if (nextpart[0] != '/') {
  316.     nextpart = NULL;
  317. #ifndef READONLY
  318.     /*
  319.      * See if we are requested to get an empty spot in the directory
  320.      * if the given name does not exist already. The value of mode is
  321.      * not important until we actually create the filelock.
  322.      */
  323.     if (!(mode & MODE_CREATEFILE)) {
  324.         mode ^= MODE_CREATEFILE;
  325.         createit = 1;
  326.     } else
  327.         createit = 0;
  328. #endif
  329.     } else
  330.     nextpart++;
  331.  
  332.     /*
  333.      * Are we at the end of the name? Then we are finished now. This works
  334.      * because sde contains the directory entry of parentdir.
  335.      */
  336.  
  337.     if (name[0] == '\0')
  338.     goto exit;
  339.  
  340.     /*
  341.      * If there is more name, we enter the directory, and here we get the
  342.      * first entry.
  343.      */
  344.  
  345.     sde.de_Sector = DirClusterToSector(sde.de_Msd.msd_Cluster);
  346.     sde.de_Offset = 0;
  347.  
  348.     if ((sector = GetSec(sde.de_Sector)) == NULL)
  349.     goto error;
  350.  
  351.     CopyMem(sector, &sde.de_Msd, (long) sizeof (struct MsDirEntry));
  352.     OtherEndianMsd(&sde.de_Msd);
  353.     FreeSec(sector);
  354.  
  355.     while (de) {
  356.     switch (CompareNames(&sde.de_Msd, component)) {
  357.     case CMP_FREE_SLOT:
  358.         if (freesec == SEC_EOF) {
  359.         freesec = sde.de_Sector;
  360.         freeoffset = sde.de_Offset;
  361.         }
  362.         /* Fall through */
  363.     case CMP_NOT_EQUAL:
  364.         de = FindNext(&sde, createit);      /* Try next directory
  365.                          * entry */
  366.         continue;
  367.     case CMP_OK_DIR:
  368.         if (name = nextpart) {
  369.         /*
  370.          * We want to keep locks on all directories between each
  371.          * bottom directory and file lock, so we can easily find
  372.          * the parent of a lock. There just seems to be a problem
  373.          * here when we enter the 'subdirectories' . or .. , but
  374.          * that in not so: MakeLock will detect that it has
  375.          * already a lock on those, and NOT make :one/two the
  376.          * parent of :one/two/.. .
  377.          */
  378.         newlock = MakeLock(parentdir, de, SHARED_LOCK);
  379.         MSUnLock(parentdir);
  380.         parentdir = newlock;
  381.         goto newdir;
  382.         }
  383.         goto exit;
  384.     case CMP_OK_FILE:
  385.         if (nextpart) {
  386.         error = ERROR_OBJECT_WRONG_TYPE;
  387.         de = NULL;
  388.         }
  389.         goto exit;
  390.     case CMP_END_OF_DIR:    /* means we will never find it */
  391.         error = ERROR_OBJECT_NOT_FOUND;
  392.         if (freesec == SEC_EOF) {
  393.         freesec = sde.de_Sector;
  394.         freeoffset = sde.de_Offset;
  395.         }
  396.         de = NULL;
  397.         goto exit;
  398.     }
  399.     }
  400.  
  401. exit:
  402.     if (de) {
  403.     newlock = MakeLock(parentdir, &sde, mode);
  404.     } else {
  405.     newlock = NULL;
  406. #ifndef READONLY
  407.     if (createit &&         /* Do we want to make it? */
  408.         error == ERROR_OBJECT_NOT_FOUND &&    /* does it not exist yet? */
  409.         nextpart == NULL) { /* do we have the last part of the name */
  410.         if (freesec != SEC_EOF) {   /* is there any room? */
  411.         if (IDDiskState == ID_VALIDATED) {
  412.             error = 0;
  413.             setmem(&sde.de_Msd, sizeof (sde.de_Msd), 0);
  414.             sde.de_Sector = freesec;
  415.             sde.de_Offset = freeoffset;
  416.             /* ToMSName(sde.de_Msd.msd_Name, name); */
  417.             strncpy(sde.de_Msd.msd_Name, component, 8 + 3);
  418.             EmptyFileLock = MakeLock(parentdir, &sde, mode);
  419.             WriteFileLock(EmptyFileLock);
  420.         } else
  421.             error = ERROR_DISK_WRITE_PROTECTED;
  422.         } else
  423.         error = ERROR_DISK_FULL;
  424.     }
  425. #endif
  426.     }
  427.  
  428. error:
  429.     MSUnLock(parentdir);
  430.  
  431.     return newlock;
  432. }
  433.  
  434. /*
  435.  * This routine DupLocks a file. This simply means incrementing the
  436.  * reference count, if it was not an exclusive Lock.
  437.  */
  438.  
  439. struct MSFileLock *
  440. MSDupLock(fl)
  441. struct MSFileLock *fl;
  442. {
  443.     if (fl == NULL)
  444.     fl = RootLock;
  445.     if (fl->msfl_Refcount <= 0) {
  446.     error = ERROR_OBJECT_IN_USE;
  447.     return NULL;
  448.     } else {
  449.     fl->msfl_Refcount++;
  450.     }
  451.  
  452.     return fl;
  453. }
  454.  
  455. /*
  456.  * This routine DupLocks the parent of a lock, if there is one.
  457.  */
  458.  
  459. struct MSFileLock *
  460. MSParentDir(fl)
  461. register struct MSFileLock *fl;
  462. {
  463.     if (fl == NULL || fl == RootLock) {
  464.     error = ERROR_OBJECT_NOT_FOUND;
  465.     } else if (fl->msfl_Parent)
  466.     return MSDupLock(fl->msfl_Parent);
  467.  
  468.     return NULL;
  469. }
  470.  
  471. /*
  472.  * This routine UnLocks a file.
  473.  */
  474.  
  475. int
  476. MSUnLock(fl)
  477. struct MSFileLock *fl;
  478. {
  479. #ifdef DEBUG
  480.     debug(("MSUnLock %08lx: ", fl));
  481.     PrintDirEntry(&fl->msfl_Msd);
  482. #endif
  483.  
  484.     if (fl) {
  485.     if (--fl->msfl_Refcount <= 0) {
  486.         struct LockList *list;
  487.  
  488.         list = (struct LockList *) fl->msfl_Node.mln_Pred;
  489.         Remove(fl);
  490.         debug(("Remove()d %08lx\n", fl));
  491.  
  492.         /*
  493.          * We may need to get rid of the LockList if it is empty. This
  494.          * is the current LockList iff we are called from
  495.          * MSDiskRemoved(). Please note that we are not even sure that
  496.          * 'list' really is the list header, therefore the careful
  497.          * test if fl refers to a volume label (root lock) which is
  498.          * finally UnLock()ed. Because of the recursion, we only try to
  499.          * free the LockList iff there is no parent anymore, since
  500.          * otherwise list may be invalid by the time we use it.
  501.          */
  502.         if (fl->msfl_Parent) {
  503.         MSUnLock(fl->msfl_Parent);
  504.         } else {
  505.         if ((fl->msfl_Msd.msd_Attributes & ATTR_VOLUMELABEL) &&
  506.             ((void *) list->ll_List.mlh_Head ==
  507.              (void *) &list->ll_List.mlh_Tail)
  508.             ) {
  509.             FreeLockList(list);
  510.         }
  511.         }
  512.         FreeMem(fl, (long) sizeof (*fl));
  513.     }
  514.     }
  515.     return DOSTRUE;
  516. }
  517.  
  518. /*
  519.  * This is (among other things) the inverse of ToMSName().
  520.  */
  521.  
  522. void
  523. ExamineDirEntry(msd, fib)
  524. struct MsDirEntry *msd;
  525. register struct FileInfoBlock *fib;
  526. {
  527.     register byte  *end,
  528.            *dot;
  529.  
  530. #ifdef DEBUG
  531.     debug(("+ "));
  532.     PrintDirEntry(msd);
  533. #endif
  534.     strncpy(&fib->fib_FileName[1], msd->msd_Name, 8);
  535.     /* Keep at least one character, even a space, before the dot */
  536.     dot = ZapSpaces(&fib->fib_FileName[2], &fib->fib_FileName[1 + 8]);
  537.     dot[0] = ' ';
  538.     strncpy(dot + 1, msd->msd_Ext, 3);
  539.     dot[4] = '\0';
  540.     end = ZapSpaces(dot, dot + 4);
  541.     if (end > dot)
  542.     dot[0] = '.';
  543.     fib->fib_FileName[0] = strlen(&fib->fib_FileName[1]);
  544.  
  545.     fib->fib_DirEntryType =
  546.     (msd->msd_Attributes & ATTR_DIR) ? FILE_DIR : FILE_FILE;
  547.     fib->fib_Protection = 0;
  548.     if (!(msd->msd_Attributes & ATTR_ARCHIVED))
  549.     fib->fib_Protection |= FIBF_ARCHIVE;
  550.     if (msd->msd_Attributes & ATTR_READONLY)
  551.     fib->fib_Protection |= (FIBF_WRITE | FIBF_DELETE);
  552.     if (msd->msd_Attributes & (ATTR_HIDDEN|ATTR_SYSTEM))
  553.     fib->fib_Protection |= FIBF_HIDDEN;
  554.     fib->fib_Size = msd->msd_Filesize;
  555.     fib->fib_NumBlocks = (msd->msd_Filesize + Disk.bps - 1) / Disk.bps;
  556.     ToDateStamp(&fib->fib_Date, msd->msd_Date, msd->msd_Time);
  557.     fib->fib_Comment[0] = 0;
  558. }
  559.  
  560. int
  561. MSExamine(fl, fib)
  562. struct MSFileLock *fl;
  563. register struct FileInfoBlock *fib;
  564. {
  565.     if (fl == NULL)
  566.     fl = RootLock;
  567.  
  568.     fib->fib_DiskKey = ((ulong) fl->msfl_DirSector << 16) | fl->msfl_DirOffset;
  569.     fib->fib_EntryType = 0;    /* No ExNext called yet */
  570.     ExamineDirEntry(&fl->msfl_Msd, fib);
  571.  
  572.     return DOSTRUE;
  573. }
  574.  
  575. int
  576. MSExNext(fl, fib)
  577. struct MSFileLock *fl;
  578. register struct FileInfoBlock *fib;
  579. {
  580.     word        sector = fib->fib_DiskKey >> 16;
  581.     word        offset = (word) fib->fib_DiskKey;
  582.     byte       *buf;
  583.  
  584.     if (fl == NULL)
  585.     fl = RootLock;
  586.  
  587.     if (fib->fib_EntryType == 0) {
  588.     fib->fib_EntryType = 1;
  589.     if (fl->msfl_Msd.msd_Attributes & ATTR_DIR) {
  590.         /* Enter subdirectory */
  591.         sector = DirClusterToSector(fl->msfl_Msd.msd_Cluster);
  592.         offset = 0;
  593.     } else
  594.         NextDirEntry(§or, &offset);
  595.     } else {
  596. skip:
  597.     NextDirEntry(§or, &offset);
  598.     }
  599.  
  600.     if (sector != SEC_EOF) {
  601.     register struct MsDirEntry *msd;
  602.  
  603.     if (buf = GetSec(sector)) {
  604.         msd = (struct MsDirEntry *) (buf + offset);
  605.         if (msd->msd_Name[0] == '\0') {
  606.         FreeSec(buf);
  607.         goto end;
  608.         }
  609.         if (msd->msd_Name[0] & DIR_DELETED_MASK ||
  610.         msd->msd_Name[0] == '.' ||      /* Hide "." and ".." */
  611.         (msd->msd_Attributes & ATTR_VOLUMELABEL)) {
  612.         FreeSec(buf);
  613.         goto skip;
  614.         }
  615.         OtherEndianMsd(msd);/* Get correct endianness */
  616.         fib->fib_DiskKey = ((ulong) sector << 16) | offset;
  617.         ExamineDirEntry(msd, fib);
  618.         OtherEndianMsd(msd);/* Get wrong endianness */
  619.         FreeSec(buf);
  620.  
  621.         return DOSTRUE;
  622.     }
  623.     }
  624. end:
  625.     error = ERROR_NO_MORE_ENTRIES;
  626.     return DOSFALSE;
  627. }
  628.  
  629. /*
  630.  * Convert AmigaDOS protection bits to messy attribute bits.
  631.  */
  632.  
  633. long
  634. MSSetProtect(parentdir, name, mask)
  635. register struct MSFileLock *parentdir;
  636. char       *name;
  637. long       mask;
  638. {
  639.     register struct MSFileLock *lock;
  640.  
  641.     if (parentdir == NULL)
  642.     parentdir = RootLock;
  643.  
  644.     lock = MSLock(parentdir, name, EXCLUSIVE_LOCK);
  645.     if (lock) {
  646.     /* Leave SYSTEM bit as-is */
  647.     lock->msfl_Msd.msd_Attributes &= ATTR_SYSTEM;
  648.     /* write or delete protected -> READONLY */
  649.     if (mask & (FIBF_WRITE|FIBF_DELETE))
  650.         lock->msfl_Msd.msd_Attributes |= (ATTR_READONLY);
  651.     /* hidden -> hidden */
  652.     if (mask & FIBF_HIDDEN)
  653.         lock->msfl_Msd.msd_Attributes |= (ATTR_HIDDEN);
  654.     /* archived=0 (default) -> archived=1 (default) */
  655.     if (!(mask & FIBF_ARCHIVE))
  656.         lock->msfl_Msd.msd_Attributes |= (ATTR_ARCHIVED);
  657.     WriteFileLock(lock);
  658.     MSUnLock(lock);
  659.     return TRUE;
  660.     }
  661.  
  662.     return FALSE;
  663. }
  664.  
  665. int
  666. CheckLock(lock)
  667. register struct MSFileLock *lock;
  668. {
  669.     register struct MSFileLock *parent;
  670.  
  671.     if (lock) {
  672.     while (parent = lock->msfl_Parent)
  673.         lock = parent;
  674.     if (lock != RootLock)
  675.         error = ERROR_DEVICE_NOT_MOUNTED;
  676.     }
  677.     return error;
  678. }
  679.  
  680. #ifndef READONLY
  681.  
  682. void
  683. WriteFileLock(fl)
  684. register struct MSFileLock *fl;
  685. {
  686.     debug(("WriteFileLock %08lx\n", fl));
  687.  
  688.     if (fl) {
  689.     register byte  *block = GetSec(fl->msfl_DirSector);
  690.  
  691.     if (block) {
  692.         CopyMem(&fl->msfl_Msd, block + fl->msfl_DirOffset,
  693.             (long) sizeof (fl->msfl_Msd));
  694.         OtherEndianMsd(block + fl->msfl_DirOffset);
  695.         MarkSecDirty(block);
  696.         FreeSec(block);
  697.     }
  698.     }
  699. }
  700.  
  701. void
  702. UpdateFileLock(fl)
  703. register struct MSFileLock *fl;
  704. {
  705.     struct DateStamp dateStamp;
  706.  
  707.     debug(("UpdateFileLock %08lx\n", fl));
  708.  
  709.     DateStamp(&dateStamp);
  710.     ToMSDate(&fl->msfl_Msd.msd_Date, &fl->msfl_Msd.msd_Time, &dateStamp);
  711.     WriteFileLock(fl);
  712. }
  713.  
  714. #endif
  715.  
  716. struct LockList *
  717. NewLockList(cookie)
  718. void           *cookie;
  719. {
  720.     struct LockList *ll;
  721.  
  722.     if (ll = AllocMem((long) sizeof (*ll), MEMF_PUBLIC)) {
  723.     NewList(&ll->ll_List);
  724.     ll->ll_Cookie = cookie;
  725.     } else
  726.     error = ERROR_NO_FREE_STORE;
  727.  
  728.     return ll;
  729. }
  730.  
  731. void
  732. FreeLockList(ll)
  733. struct LockList *ll;
  734. {
  735.     debug(("FreeLockList %08lx\n", ll));
  736.  
  737.     if (ll) {
  738.     MayFreeVolNode(ll->ll_Cookie);  /* not too happy about this */
  739.     FreeMem(ll, (long) sizeof (*ll));
  740.     if (ll == LockList)     /* locks on current volume */
  741.         LockList = NULL;
  742.     }
  743. }
  744.